package com.lecyon.farm.service.impl;

import com.alibaba.fastjson.JSONObject;
import com.google.common.collect.Maps;
import com.google.gson.Gson;
import com.lecyon.farm.service.IQiniuService;
import com.lecyon.farm.service.IUploadTokenService;
import com.qiniu.http.Response;
import com.qiniu.storage.Configuration;
import com.qiniu.storage.Region;
import com.qiniu.storage.UploadManager;
import com.qiniu.storage.model.DefaultPutRet;
import lombok.NonNull;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections.MapUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.http.HttpEntity;
import org.apache.http.client.ClientProtocolException;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.entity.ContentType;
import org.apache.http.entity.mime.MultipartEntityBuilder;
import org.apache.http.entity.mime.content.InputStreamBody;
import org.apache.http.entity.mime.content.StringBody;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.util.EntityUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Lazy;
import org.springframework.stereotype.Service;

import java.io.IOException;
import java.io.InputStream;
import java.util.Map;
import java.util.Set;

/**
 * @author Yao Zheng
 * @Date 2019/10/12 15:07
 */
@Service
@Slf4j
public class QiniuServiceImpl implements IQiniuService {

    private IUploadTokenService uploadTokenService;

    @Value("${qiniu.upload.url}")
    private String uploadUrl;

    @Value("${qiniu.path}")
    private String downloadUrlPrefix;

    /**
     * 通过七牛上传文件到七牛云服务器
     *
     * @param fileName    文件名
     * @param inputStream 文件输入流
     * @return
     * @throws IOException
     */
    @Override
    public String uploadFileToQiniu(@NonNull String fileName, @NonNull InputStream inputStream) throws IOException {
        StringBuffer downLoadUrl = new StringBuffer();
        downLoadUrl.append(downloadUrlPrefix).append("/").append(fileName);
        // 构造一个带指定Zone对象的配置类,指定机房所在区域
        Configuration cfg = new Configuration(Region.huanan());
        // 其他参数参考类注释
        UploadManager uploadManager = new UploadManager(cfg);
        String token = uploadTokenService.getUploadToken();
        //默认不指定key的情况下，以文件内容的hash值作为文件名
        String key = fileName;
        Response response = uploadManager.put(inputStream, key, token, null, null);
        if (response.isOK()) {
            return downLoadUrl.toString();
        } else {
            //解析上传结果
            DefaultPutRet putRet = new Gson().fromJson(response.bodyString(), DefaultPutRet.class);
            return putRet.toString();
        }
    }

    /**
     * 通过七牛上传文件到七牛云服务器
     *
     * @param fileName    文件名
     * @param inputStream 文件输入流
     * @return
     * @throws IOException
     */
    @Override
    public String uploadFile(@NonNull String fileName, @NonNull InputStream inputStream) throws IOException {
        String token = uploadTokenService.getUploadToken();
        Map<String, String> uploadParams = Maps.newLinkedHashMap();
        uploadParams.put("token", token);
        HttpPost httppost = new HttpPost(uploadUrl);
        InputStreamBody streamBody = new InputStreamBody(inputStream, ContentType.APPLICATION_OCTET_STREAM, fileName);
        MultipartEntityBuilder multipartEntityBuilder = MultipartEntityBuilder.create();
        multipartEntityBuilder.addPart("file", streamBody);
        setUploadParams(multipartEntityBuilder, uploadParams);
        HttpEntity reqEntity = multipartEntityBuilder.build();
        httppost.setEntity(reqEntity);
        CloseableHttpResponse response = null;
        String respStr = "";
        String downloadUrl = "";
        try {
            CloseableHttpClient httpclient = HttpClients.createDefault();
            response = httpclient.execute(httppost);
            HttpEntity resEntity = response.getEntity();
            respStr = getRespString(resEntity);
            JSONObject jsonObject = JSONObject.parseObject(respStr);
            downloadUrl = String.valueOf(jsonObject.get("downloadUrl"));
            if (!StringUtils.isEmpty(downloadUrl)) {
                downloadUrl += "?attname=" + fileName;
            }
            log.info("upload file successfully, response is :{}", respStr);
            EntityUtils.consume(resEntity);
        } catch (ClientProtocolException e) {
            log.error("upload file failed:{}", e.getMessage());
            throw e;
        } catch (IOException e) {
            log.error("upload file failed:{}", e.getMessage());
            throw e;
        } finally {
            if (response != null) {
                response.close();
            }
        }
        return downloadUrl;
    }

    /**
     * 设置上传文件时所附带的其他参数
     *
     * @param multipartEntityBuilder
     * @param params
     */
    private void setUploadParams(MultipartEntityBuilder multipartEntityBuilder, Map<String, String> params) {
        if (MapUtils.isNotEmpty(params)) {
            Set<String> keys = params.keySet();
            for (String key : keys) {
                multipartEntityBuilder.addPart(key, new StringBody(params.get(key), ContentType.TEXT_PLAIN));
            }
        }
    }

    /**
     * 将返回结果转化为String
     *
     * @param entity
     * @return
     * @throws IOException
     * @throws IllegalStateException
     * @throws Exception
     */
    private String getRespString(HttpEntity entity) throws IllegalStateException, IOException {
        if (entity == null) {
            return null;
        }
        InputStream is = entity.getContent();
        StringBuffer strBuf = new StringBuffer();
        byte[] buffer = new byte[4096];
        int r;
        while ((r = is.read(buffer)) > 0) {
            strBuf.append(new String(buffer, 0, r, "UTF-8"));
        }
        return strBuf.toString();
    }

    /**
     * ----------------------------- 分割线 以下是setter方法，用于替换field上的@Autowired -----------------------------
     **/

    @Autowired
    @Lazy
    public void setUploadTokenService(IUploadTokenService uploadTokenService) {
        this.uploadTokenService = uploadTokenService;
    }
}
